﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Serialization;

using Refix.Core.IO;
using Refix.Core.Properties;
using Refix.Core.Structure;

namespace Refix.Core
{
    static public class Extensions
    {
        static private readonly Regex _validPart = new Regex(@"^\*|(\d+\+?)$");

        static public bool IsNullOrEmpty(this string input)
        {
            return string.IsNullOrEmpty(input);
        }

        static public bool IsMatchFor(this string version, string pattern)
        {
            if (version == pattern)
            {
                return true;
            }
            string[] versionParts = version.Split('.');
            string[] patternParts = pattern.Split('.');
            if (patternParts.Length > versionParts.Length)
            {
                return false;
            }
            for (int i = 0; i < patternParts.Length; i++)
            {
                if (!_validPart.IsMatch(patternParts[i]))
                {
                    return false;
                }
                if (patternParts[i] == "*")
                {
                    continue;
                }
                int thisVersionPart = int.Parse(versionParts[i], CultureInfo.InvariantCulture);
                int thisPatternPart = int.Parse(patternParts[i].Replace("+", ""), CultureInfo.InvariantCulture);
                if (patternParts[i].Contains("+") && thisVersionPart < thisPatternPart)
                {
                    return false;
                }
                if (!patternParts[i].Contains("+") && thisVersionPart != thisPatternPart)
                {
                    return false;
                }
            }
            return true;
        }

        static public string ToPublicKeyTokenString(this byte[] publicKeyToken)
        {
            return BitConverter.ToString(publicKeyToken).Replace("-", "").ToLowerInvariant();
        }

        static public bool Contains(this Project project, string assemblyName, string version)
        {
            return project.References.Contains(assemblyName, version)
                   || project.ProjectReferences.Any(p => p.Contains(assemblyName, version));
        }

        static public bool Contains(this IEnumerable<BinaryReference> references, string assemblyName, string version)
        {
            return references.Any(r =>
                                  string.Equals(r.Name, assemblyName, StringComparison.OrdinalIgnoreCase) &&
                                  r.OriginalVersion == version)
                   || references.Any(r => r.References.Contains(assemblyName, version));
        }

        static public ProjectFile GetDependencyFile(this ProjectFile projectFile)
        {
            ProjectFile dependencyFile;
            using (FileStream fileStream = File.OpenRead(projectFile.FileName + FileExtensions.DependencyFile))
            {
                dependencyFile = (ProjectFile)new XmlSerializer(typeof(ProjectFile)).Deserialize(fileStream);
            }
            return dependencyFile;
        }

        static public bool IsSystemAssemblyName(this string name)
        {
            if (name.StartsWith("System.Web.Mvc")) return false;
            if (name.StartsWith("System.Web.Abstractions")) return false;
            if (name.StartsWith("System.Web.Routing")) return false;
            if (name.StartsWith("System.Web.DataVisualization")) return false;
            Assembly assembly;
            try
            {
#pragma warning disable 612,618
                assembly = Assembly.LoadWithPartialName(name);
#pragma warning restore 612,618
            }
            catch
            {
                return false;
            }
            if (assembly != null && assembly.IsSystemAssembly())
            {
                return true;
            }
            return false;
        }

        static private bool IsSystemAssembly(this Assembly assembly)
        {
            object[] customAttributes = assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), true);
            if (customAttributes.Length == 0)
            {
                return false;
            }
            switch (((AssemblyProductAttribute)customAttributes[0]).Product)
            {
                case "Microsoft® .NET Framework":
                case "Microsoft® Visual Studio® 2008":
                case "Microsoft (R) Visual Studio (R) 2005":
                case "Microsoft (R) Visual Studio (R) 2010":
                    return true;
                default:
                    return false;
            }
        }

        static public Position PositionOf<T>(this IEnumerable<T> enumerable, T item) where T : class
        {
            return item == enumerable.Last()
                       ? Position.Last
                       : item == enumerable.First()
                             ? Position.First
                             : Position.Normal;
        }

        static public bool CheckBackupFileDoesNotExist(this ProjectFile projectFile)
        {
            if (File.Exists(projectFile.FileName + FileExtensions.BackupFile))
            {
                OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("INJECT_EXISTING_BACKUP_FILE"),
                                   Path.GetFileName(projectFile.FileName) + FileExtensions.BackupFile);
                return false;
            }
            return true;
        }

        static public bool CheckDependencyFileExists(this ProjectFile projectFile)
        {
            if (!File.Exists(projectFile.FileName + FileExtensions.DependencyFile))
            {
                OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("INJECT_NO_DEPENDENCY_FILE"),
                                   Path.GetFileName(projectFile.FileName));
                return false;
            }
            return true;
        }
        
        static public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
        {
            foreach (var item in enumerable)
            {
                action(item);
            }
        }
    }
}